<?php
/*
This file 'pps.php' is part of the PPS project <http://code.google.com/p/fracsnetpps/>

Copyright: (C) 2009 Arthur, B. aka ]{ing <whinemore@gmail.com>

 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 2
 of the License, or (at your option) any later version.
 .
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 GNU General Public License for more details.
 .
 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 .

*/
ini_set('display_errors', 1);
error_reporting(E_ALL);

$INFO= array();

include "refresh.php";
include "pps_player.php";
include "pps_base.php";
require ("ppsconfig.php");

define('FRESH', 1);
define('CONNECTED', 2);
define('RECONNECTING', 4);
define('DISCONNECTED', 8);
define('IDLE', 16);

class soldat_server{

    public $m_ip;
    public $m_port;
    public $m_adminlog;
    
    public $m_sock;
    public $m_buffer;
    
    public $State;
    
    public $stats; /* Note: Initialize outside the class! */
    
    public $join_try; /* HACK REMOVE ME */
    
    public $refresh;
    public $m_timeout;
    
    public function __construct($ip, $port, $adminlog, $timeout = 10, $reconnect = true ){
        $this->m_ip = $ip;
        $this->m_port = $port;
        $this->m_adminlog = $adminlog;
        $this->m_timeout = $timeout;
        $this->m_retry = $reconnect;   
        
        $this->State = 0;
        $this->State |= FRESH;
        
        $this->stats = null;
        $this->join_try = null;
        
        $this->m_sock = socket_create( AF_INET, SOCK_STREAM, SOL_TCP );
    }
	/* ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- */   
    public function connect($timeout = 0){
	/* ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- */        
        $this->m_timeout = $timeout;
        
        if( !socket_connect( $this->m_sock, $this->m_ip, $this->m_port) ){
            $this->State |= DISCONNECTED;
            return 1; /* Error */
        }else{
            $logstr = $this->m_adminlog . "\r\n";
            socket_write( $this->m_sock, $logstr );
            $this->State = CONNECTED;
        }
    }
	/* ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- */    
    public function get_refresh(){
	/* ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- */    
        $sock = fsockopen( $this->m_ip, $this->m_port );
        $admin = "$this->m_adminlog\r\n";
        fputs($sock, $admin);
        fputs($sock, "REFRESH\r\n");
        $buffer = "";
        while( $buffer != "REFRESH" ){
            $buffer = trim(fgets($sock, 1024));
            if( !$buffer ) continue;
            else if($buffer == "REFRESH") break;
        }
        
        $info = GetSoldatInfo($sock);
        
        fclose($sock);
        
        return $info;
    }
}
/*//////////////////////////////////////////////////////////////////////////////////////////////////////////////// */        
class pps{
/*//////////////////////////////////////////////////////////////////////////////////////////////////////////////// */

    /* General info */
    private    $m_ip;
    private $m_port;
    private $m_adminlog;
    private $m_sock;

    /* Database info */
    private $m_pps_db;
    private $m_db_ip;
    private $m_db_pass;
    private $m_db_user;
    private $m_db_name;

    /* Stats info */
    private $m_buffer;
    private $stats;
    private $m_connected;
    
    /* Number of players needed to rate */
    private $m_rate;
    private $m_start;
    private $m_version;
    
    /* Use echo-mode */
    private $m_printc_kills;
    private $m_prints_general;
    private $m_printc_general;
    
    private $m_debug;
    
    private $m_TPC;		/* Total Player count */
    private $m_SQL_ON; /* Boolean */
    
    public $servers; /* Server Array */
    
    public $prep;
	/* ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- */    
        public function __construct(    $s_ip           = "localhost",          
                                        $s_port         = "20202", 
                                        $s_pass         = "",
                                        $db_ip          = "localhost", 
                                        $db_pass        = "", 
                                        $db_user        = "root" , 
                                        $db_name        = "pps", 
                                        $debug          = false, 
                                        $rate_at        = 5, 
                                        $silent         = true, 
                                        $irc_adm        = false){ /* IRC admin is deprecated */

                                        
	/* ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- */                                    
        $this->m_start = time();
        $this->m_version = "v1.0.1g updated(07/16/09)";
        
        /*FIXME: Fast hack to initialize the server info */
        $this->servers = array();
        $this->servers[0] = new soldat_server( "67.202.73.146", "23000", $s_pass );
        $this->servers[1] = new soldat_server( "67.202.73.146", "23001", $s_pass );
        
        $this->m_connected = false;
        
        $this->m_db_ip = $db_ip;
        $this->m_db_pass = $db_pass;
        $this->m_db_user = $db_user;
        $this->m_db_name = $db_name;

        $this->m_rate = $rate_at;
        
        $this->m_TPC = 0;
        $this->m_SQL_ON = true;
    }
    
    function __destruct(){
    	if ($this->m_pps_db){
        	mysqli_query($this->m_pps_db, "UPDATE status SET stats_on=0 WHERE stats_version='v0.4b'");
        	mysqli_close($this->m_pps_db);
    	}
    }
    private function disconnect_mysql(){
    	if ($this->m_pps_db){
    		mysqli_close($this->m_pps_db);
    		$this->m_pps_db = null;
    	}
    	$this->m_SQL_ON = false;
    }
	/* ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- */    
    private function connect_mysql(){
	/* ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- */    

    	if ($this->m_pps_db){
    		mysqli_close($this->m_pps_db);
    		$this->m_pps_db = null;
    	}
    	
    	$this->m_pps_db = new mysqli($this->m_db_ip, $this->m_db_user, $this->m_db_pass, $this->m_db_name);
        $this->prep = $this->m_pps_db->stmt_init();
        
        $prepare_str  = "UPDATE players SET kills=?,";
        $prepare_str .= "deaths=?,";
        $prepare_str .= "doubles=?,";
        $prepare_str .= "triples=?,";
        $prepare_str .= "multi=?,";
        $prepare_str .= "caps=?,";
        $prepare_str .= "grabs=?,";
        $prepare_str .= "returns=?,";
        $prepare_str .= "kd=?,";
        $prepare_str .= "cg=?,";
        $prepare_str .= "ck=?,";
        $prepare_str .= "rating=?,";
        $prepare_str .= "wins=?,";
        $prepare_str .= "maps=?,";
        $prepare_str .= "time_played=?,";
        $prepare_str .= "lastplayed=NOW(),";
        $prepare_str .= "`Desert Eagles`=`Desert Eagles`+?,";
        $prepare_str .= "`HK MP5`=`HK MP5`+?,";
        $prepare_str .= "`Ak-74`=`Ak-74`+?,";
        $prepare_str .= "`Steyr AUG`=`Steyr AUG`+?,";
        $prepare_str .= "`Spas-12`=`Spas-12`+?,";
        $prepare_str .= "`Ruger 77`=`Ruger 77`+?,";
        $prepare_str .= "`M79`=`M79`+?,";
        $prepare_str .= "`Barrett M82A1`=`Barrett M82A1`+?,";
        $prepare_str .= "`FN Minimi`=`FN Minimi`+?,";
        $prepare_str .= "`Selfkill`=`Selfkill`+?,";
        $prepare_str .= "`Combat Knife`=`Combat Knife`+?,";
        $prepare_str .= "`Chainsaw`=`Chainsaw`+?,";
        $prepare_str .= "`LAW`=`LAW`+?,";
        $prepare_str .= "`Grenade`=`Grenade`+?,";
        $prepare_str .= "streak=?,";
        $prepare_str .= "plusminus=?,";                
        $prepare_str .= "mu=?,";
        $prepare_str .= "sigma=?,";
        $prepare_str .= "dominations=?,";
        $prepare_str .= "old_rating=?";
        $prepare_str .= " WHERE ip=?";
        
        $this->prep->prepare($prepare_str) or die("COULD NOT PREP");
        
        $this->m_SQL_ON = true;	
    }
	/* ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- */    
    public function pps_connect(){
	/* ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
        echo "--> Connecting..";
        foreach( $this->servers as $server ){
            if( $server->connect() ){
                /* Error */
                echo "\nFATAL ERROR: Could NOT connect to the soldat server!\n";
                echo "ERROR: ", socket_strerror(socket_last_error) , "\n";
                exit(socket_last_error);
            }else{                  
                echo ".";
            }
        }

		$this->connect_mysql();
		
        echo ".";
        
        if( !($this->m_pps_db) ){
            echo "\nFATAL ERROR: Unable to connect to the database\n";
            exit();
        }
            
        $this->m_connected = true;
        echo ". OK\n";
            
    }
	/* ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
    private function f__init_irc(){    /*     *****************************************
                                        * Connect to irc..(quakenet) #g.bt        *
                                        * TODO: get rid of some hard coded stuff*
                                        * add error checking                    *
                                        ***************************************** */
	/* ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- */            
    }    

	/* ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
    public function pps_monitor(){        /*******************************************************
                                         *     Main monitoring function PROXY will setup          *
                                         *    the enviornment and load mode apropriate functions *
                                         *******************************************************/
	/* ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
        if(!$this->m_connected) return;
        
        set_time_limit(0);
        
        $this->m_buffer = '';
        
        foreach( $this->servers as $key => $server ){
            //if( $server->Status & CONNECTED ){
                $server->stats = new base_stats( $this->m_pps_db, $this->servers[$key]->m_sock, $this->servers[$key]->m_buffer, $this->prep, $this->servers[$key]->get_refresh());
                $this->m_TPC += $server->stats->pc;
                echo "Found available server, hoocking stats\n";
            //}
        }

        
        mysqli_query($this->m_pps_db, "UPDATE status SET stats_on=1 WHERE stats_version='v0.4b'"); /* LEGACY CODE needs to be removed */
        
        echo "--> Now monitoring...\n";

        $this->f_monitor();
    
        //echo "--> Ubnormal Termination => 'connection lost'\n\r";
        foreach( $this->servers as $server ){
            socket_close($server->m_sock);
        }
        $this->m_is_connected = false;
    }
	/* ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
    private function f_monitor(){
	/* ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- */

    /* Live Monitoring function, runs with no debugging output or commands */
        $sol_server = null;
        
        do
        {
        
            $sol_server = array( $this->servers[0]->m_sock, $this->servers[1]->m_sock );
            
            if( false === socket_select( $sol_server, $w = NULL, $e = NULL, NULL) ){
                echo "Socket select failed\n";
                break;
            }else{
                foreach( $sol_server as $server ){
                    $read = trim(socket_read( $server, 1024, PHP_NORMAL_READ));
                    /* After Much testing the below line seems necessary:
                        Because PHP_NORMAL_READ reads untill it finds a '\0' '\n' OR '\r'
                        It will stop reading at a '\r' in this case and the second time the 
                        script loops trough the sockets it will have to do a read again JUST FOR THE '\n'
                        so the bellow line is here to do a dummy read and free up recources. */
                    socket_read( $server, 1, PHP_NORMAL_READ ); 
                    if( $server === $this->servers[0]->m_sock ){
                        $this->servers[0]->m_buffer = $read;
                        if( $this->parse_buffer( 0 ) ){
                            echo "Failsafe \n";
                            return;
                        }
                    }
                    elseif( $server === $this->servers[1]->m_sock ){
                        $this->servers[1]->m_buffer = $read;
                        if( $this->parse_buffer( 1 ) ){
                            echo "Failsafe \n";
                            return;
                        }
                    }
                 }
            }
			
			if ( $this->m_SQL_ON && !$this->m_TPC ){
				$this->disconnect_mysql();
				echo "---> !NO PLAYERS PRESENT FREEING MYSQL RESOURCE!\n";
			}
        }while( true );
        
    }
	/* ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- */    
    public function parse_buffer($server_num){
	/* ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- */

            /* NOTE: remove 'debugging' echo(s) */
            $server = $this->servers[$server_num];
            /* Grab players ip that is trying to join */
            if( strpos($server->m_buffer, "joining game (") )
            {
                $start = strpos( $server->m_buffer, "joining game (");
                $start+= 14;
                $end = strpos( $server->m_buffer, ":" , $start);
                
                $server->join_try = substr( $server->m_buffer, $start, ($end - $start));
                //echo "Join try: ", $server->join_try , "\n";
                return;
            }
            /* Check if the a player joined */
            if( substr($server->m_buffer, 0, 5) == "PJOIN" )
            {
            	if (!$this->m_SQL_ON){
            		$this->connect_mysql();
            	}
                //echo "trying :", $server->join_try , "\n";
                echo "-->[2300$server_num] ";
                $server->stats->ch_join($server->join_try);
                $server->join_try = "";
                
                $this->m_TPC ++;
                return;
            }
            if( substr($server->m_buffer, 0, 5) == "PLEFT" ){
                echo "-->[2300$server_num] ";
                $server->stats->ch_left();
                $this->m_TPC --;
                return;
            }
            if( strpos($server->m_buffer, "!rating") ){
                $name = substr($server->m_buffer, 1, strpos($server->m_buffer, "!rating") - 3);
                echo "-->[2300$server_num] Ratings request: " , $name , "\n";
                if( array_key_exists($name, $server->stats->T->ps) ){
                    $P = &$server->stats->T->ps[$name];
                    socket_write($server->m_sock, "/pm ". $P->p_id . " Rating: " . round($P->rating,2) . "\r\n");
                }
                
                return;
            }
            if( substr($server->m_buffer, 0, 6) == "NEWMAP" ){
                    echo "-->[2300$server_num] New Map Found\n";
                    
                    $server->stats->ch_nextmap();
                    echo "-->[2300$server_num] New Map Procedure finished pc=", $server->stats->T->pc, "\n";
                    return;
            }
            /* Failsafe */
            if( substr($server->m_buffer,0,8) ==  "/quitpps" )
            {
                echo "--> Failsafe\n";
                return true;
            }
            if( $server->stats->T->pc > 5 ) /* Rate only when ... how many people in the server ? default: >0 */
            {
                /* Kills and Deaths */
                if( strpos($server->m_buffer, "killed (") )
                    $server->stats->ch_kill(); 
                /* Grabs */
                elseif( strpos($server->m_buffer, "captured the") )
                    $server->stats->ch_grab();
                /* Caps */
                elseif( strpos($server->m_buffer, "scores for") )
                    $server->stats->ch_cap();
                /* Returns */
                elseif( strpos($server->m_buffer, "returned the") ) 
                    $server->stats->ch_return();
            }
    }
}

$test = new pps($SOLDAT_SERVER,$SOLDAT_PORT,$SOLDAT_ADMLOG,$MYSQL_SERVER,$MYSQL_PASSWORD,$MYSQL_USER,$MYSQL_DB);//,true,5,true,false );


$test->pps_connect();
$test->pps_monitor();

?>